﻿
using AutoMapper;
using HamcoWcs.Contract.ContractPcon;
using HamcoWcs.Models.DbInfos;
using HamcoWcs.Models.Devices;
using HamcoWcs.Models.PlcInfos;
using HamcoWcs.DAL;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using HamcoWcs.Models.Common.Enums;
using HamcoWcs.Service.Common;
using System;
using HamcoWcs.Contract;
using HamcoWcs.Models.TibcoMessage;
using HamcoWcs.Models.DeviceMsgs;
using HamcoWcs.Models.Common;
using HamcoWcs.Models.NodeInfos;

namespace HamcoWcs.Service.Pcon
{
    [AutoInject(typeof(IPconBaseService), InjectType.Single)]
    public class PconBaseService : SingleServiceBase, IPconBaseService
    {
        private object _lock = new object();
        private Dictionary<string, PconPlc> _conveyorDic = new Dictionary<string, PconPlc>();
        //private Dictionary<string, MachineDto> _machineDic = new Dictionary<string, MachineDto>();
        private readonly AutomaticStorageInfo _asrs;

        public PconBaseService(IMapper mapper, IServiceScopeFactory scopeFactory, AutomaticStorageInfo asrs) : base(mapper, scopeFactory)
        {
            _asrs = asrs;
        }

        public List<NodeInfoDto> GetMachines()
        {
            return _asrs.Nodes.Where(x => x.DeviceType != EnumNodeType.srm).ToList();
        }

        public List<PconPlc> GetAllPconPlcs()
        {
            if (_conveyorDic.Count <= 0)
            {
                _conveyorDic = InitPcons();
            }

            return _conveyorDic.Values.ToList();
        }

        public PconDto GetPcon(string machineName, string portName)
        {
            foreach (var plc in _conveyorDic.Values)
            {
                foreach (var pcon in plc.Pcons.Values)
                {
                    if (pcon.MachineName == machineName && pcon.PortName == portName)
                    {
                        return pcon;
                    }
                }
            }

            return null;
        }

        public PconPlc GetPconPlc(string plcName)
        {
            if (_conveyorDic.Count <= 0)
            {
                _conveyorDic = InitPcons();
            }

            PconPlc conveyor;
            if (_conveyorDic.TryGetValue(plcName, out conveyor))
            {
                return conveyor;
            }
            return null;
        }

        public Dictionary<string, PconPlc> InitPcons()
        {
            return _asrs.ConveyorDic;
            //lock (_lock)
            //{
            //    Dictionary<string, PconPlc> conveyorDic = new Dictionary<string, PconPlc>();
            //    try
            //    {
            //        using (var scope = _scopeFactory.CreateScope())
            //        {
            //            var context = scope.ServiceProvider.GetRequiredService<WcsDbContext>();
            //            var conveyorInfos = context.PlcInfos.Where(x => x.PlcType.Equals(GlobalValue.PALLET_PLC_TYPE, StringComparison.OrdinalIgnoreCase)).Include(x => x.DbInfos).AsNoTracking().ToList();


            //            if (conveyorInfos.Count <= 0)
            //            {
            //                return conveyorDic;
            //            }

            //            foreach (var conveyorInfo in conveyorInfos)
            //            {
            //                var conveyor = new PconPlc(conveyorInfo.PlcName);
            //                conveyor.PconPlcInfo = _mapper.Map<PlcInfoDto>(conveyorInfo);
            //                conveyor.PconDbInfo = _mapper.Map<IEnumerable<DbInfoDto>>(conveyorInfo.DbInfos).ToList();
            //                var conveyorAddInfoEntitys = context.PconInfos.Where(x => x.PlcName == conveyorInfo.PlcName).AsNoTracking().ToList();
            //                var conDtos = _mapper.Map<List<PconDto>>(conveyorAddInfoEntitys);
            //                foreach (var conDto in conDtos)
            //                {
            //                    //if (conDto.PconType == EnumPconType.BoxOut) conDto.PortState = "LC";
            //                    conveyor.Pcons.TryAdd(conDto.PconName, conDto);

            //                    var node = _asrs.Nodes.FirstOrDefault(x => x.NodeName.Equals(conDto.MachineName, StringComparison.OrdinalIgnoreCase));

            //                    node.Pcons.Add(conDto);
            //                    conDto.Machine = node;

            //                    //AddMachine(conDto);
            //                }
            //                conveyorDic.TryAdd(conveyorInfo.PlcName, conveyor);
            //            }
            //            return conveyorDic;
            //        }
            //    }
            //    catch (Exception e)
            //    {
            //        return null;
            //    }
            //}

        }



        public List<Pallet> InventoryPalletDataReport()
        {
            var pallets = new List<Pallet>();


            foreach (var plc in _conveyorDic.Values.ToList())
            {
                if (!plc.ConnectionStatus)
                    ConnectToPlc(plc);
                if (!plc.ConnectionStatus) continue;
                var dbInfo = plc.DbInfo.FirstOrDefault(x => x.DbName == "recv");
                if (dbInfo == null) continue;
                byte[] recv = new byte[dbInfo.DbLength];
                var res = plc.Client.DBRead(dbInfo.DbNum, dbInfo.StartPoint, dbInfo.DbLength, recv);

                // 读取时断开连接error
                if (res == 0x00000009) continue;
                lock (plc.Pcons)
                {
                    foreach (var pcon in plc.Pcons.Values.ToList())
                    {

                        var msg = recv.Skip(pcon.RecvStartPoint).Take(GlobalValue.CV_RECV_MSG_SIZE).ToArray();
                        var msgDto = new PconRecvMsg(msg);
                        pcon.Update(msgDto);
                        if (string.IsNullOrEmpty(pcon.UnitId)) continue;
                        pallets.Add(new Pallet
                        {
                            CurrentPositionName = pcon.PortName,
                            CurrentPositionType = "PORT",
                            CurrentZoneName = "",
                            PalletLocState = "",
                            PalletName = pcon.UnitId,
                            TransferState = "MOVING"
                        });
                    }
                }
            }


            return pallets;
        }

        private void ConnectToPlc(PconPlc pconPlc)
        {
            int connectRe = pconPlc.Client.ConnectTo(pconPlc.PlcInfo.PlcIp, 0, 1);
            if (connectRe == 0)
            {
                pconPlc.ConnectionStatus = true;
                return;
            }
            pconPlc.ConnectionStatus = false;
        }

        public List<PconDto> GetAllPcons()
        {
            var pcons = new List<PconDto>();

            foreach (var plc in _conveyorDic.Values)
            {
                pcons.AddRange(plc.Pcons.Values.ToList());
            }

            return pcons;
        }
    }
}